Inside JavaScript: Understanding Type Coercion
Inside JavaScript: Understanding Type Coercion
Previous | Next | |
---|---|---|
So, How Hard Do You Hit the Keyboard? | Up | Type Coercion: The Mostly Sensible Bits |
Type Coercion: The Sensible Bits
Transforming a String to a Number
Take this somewhat arbitrary snippet of JavaScript:
var strValue = "-1" // strValue is a character string
+strValue // Returns the numeric value -1
But wait a minute, the variable strValue
contains a character string, and everyone knows that character strings cannot necessarily be converted to numbers!
This is quite correct; but in this case, JavaScript looks at the operation we want to perform and tries to be helpful in the following ways…
- The value supplied in the variable
strValue
is the character string"-1"
- The unary1
+
operator now attempts to squeeze a numeric value out of the character string"-1"
-
Phew, we’ve been lucky!! String value
"-1"
converts nicely to the numeric value-1
WARNING
Don’t be misled by the use of the “plus” symbol for this operator. This operator returns only the numeric value of its operand, not its positive numeric value.
This is why
+"-1"
gives back-1
not+1
!
So, we can see that under the surface, JavaScript has automatically converted (or coerced) a character string into a number for us.
This is an example of where we explicitly instruct the coding to perform type coercion, because we expect to get a useful result.
But what about this situation:
var strValue = "cat" // strValue is a character string
+strValue // Returns the special value NaN (Not a Number)
Sorry, not this time!
The logic of coding is exactly the same.
All that has changed is the value stored in variable strValue
: now it is "cat"
, whereas before it was "-1"
.
JavaScript attempts to derive the numerical value of the character string "cat"
, so although NaN
is technically the correct answer, it is unhelpful—especially if the code that follows is expecting to receive a number.
So here is an example of where the same piece of coding will behave in two very different ways depending on what value happens to be stored in the variable strValue
.
Type coercion does not always do either what you want, or what you might expect.
Overloading the +
Operator
So, what would you expect to happen in this situation?
1 + 2 // 3 Trick question :-)
Here, we are using +
as the binary operator for arithmetic addition.
Since both operands are numeric, everything is fine and we get the expect answer 3
.
But what happens in these situations?
1 + "2" // "12"
"3" + 4 // "34"
Buh!?
Here, we have a situation in which we are trying to perform the arithmetic operation of addition on one or more non-numeric values.
In order for an arithmetic operation to be successful, both operands must be numeric.
Q: Is it safe simply to assume that both operands can be converted to numbers and then added?
A: It’s probably foolish to try to discover the numeric value of a "cat"
…
So, when it comes to converting between strings and numbers, the safety of type coercion only works in one direction:
UNSAFE: Not all string values have a numeric representation
SAFE: All numbers have a string representation
So JavaScript automatically and silently does two things here:
- It identifies that one of the operands to the
+
operator is non-numeric - It coerces the non-numeric operand to a string
- It further coerces the
+
operator to perform string concatenation instead of arithmetic addition
Operation coercion is also known as “overloading”.
This is where the “+
” symbol switches from performing arithmetic addition, and instead, performs string concatenation.
All of this happens silently and depends on the datatype of the arguments it receives at runtime.
Consequently, 1 + "2"
means that the numeric 1
is first converted to character "1"
, then "1"
and "2"
are concatenated giving "12"
.
The same process applies to "3" + 4
in order to give "34"
.
Ok, let’s mix it up a little more. What about this expression:
1 + 2 + "3" + 4 // "334"
What the flagnog!
To understand what’s going on here, let’s break this instruction down the way JavaScript sees it:
- Firstly, at any one time, the infix
+
operator can only operate on two arguments at any one time - The first part of the expression (
1 + 2
) is a perfectly valid arithmetic operation, so addition is performed and the intermediate result3
is substituted into the expression at this point - Our expression now looks like this
3 + "3" + 4
- The first part of this expression is now
3 + "3"
, but since one of the operands is a string, JavaScript converts the numeric operand value to a string, coerces the+
operator from arithmetic addition to string concatenation, and joins the two strings together giving another intermediate result of"33"
"33"
is then substituted back into the original expression to give"33" + 4
- The same logic about operands of mixed datatype is applied and the final result is
"334"
- Simples!
Transforming a Boolean to a Number
Let’s try these examples:
var boolVal1 = true
var boolVal2 = false
+boolVal1 // Numeric 1
+boolVal2 // Numeric 0
Again, we go through the same sequence of logic:
- The unary
+
operator attempts to return the numeric representation of its operand - The variables
boolVal1
andboolVal2
contain the valuestrue
andfalse
thus making them both of typeBoolean
- The Boolean values
true
andfalse
are represented by the single bits1
and0
respectively, and these convert directly to the integers1
and0
- Consequently,
+true
is1
and+false
is0
Knowing then that Boolean values can be directly coerced to the integers 1
or 0
, the following statements now should make sense:
1 + true // 2
1 + false // 1
Transforming a Number to a Boolean
Ok, let’s try some examples the other way around:
var boolVal = false
var numVal = 2
!boolVal // true - no surprises here I hope
!numVal // false - hmmmm?
The logical NOT operator !
is another unary operator that expects a Boolean operand.
In the first example, there’s no problem because false
is a Boolean value and when the NOT operator is applied, we get the expected value of true
.
However, in the second example, !
has been passed an integer.
- Before we can take the logical NOT of an integer, that integer must first be coerced to a Boolean value.
- The rule JavaScript follows is simply this: irrespective of their sign or magnitude, all non-zero numbers coerce to
true
. - Zero is the only number which coerces to
false
.
Code Minimizers
JavaScript code minimizers seek to reduce your source code down to the smallest possible representation.
By taking advantage of this type coercion behaviour, the Boolean keywords true
and false
can be reduced from 4 or 5 bytes, down to just 2.
!0
is used to representtrue
since integer0
coerces tofalse
, and!false
istrue
!1
is used to representfalse
since integer1
coerces totrue
, and!true
isfalse
Looping Using Boolean Type Coercion
Here’s another type coercion trick that can be used if you have a loop that should stop after counting down to zero:
var n = 5;
while (n--) {
console.log(`Stop when n = 0. n is now ${n}`);
}
Here, we are relying on the fact that all non-zero integers coerce to true
; thus as long as n
remains greater than zero, the condition evaluated by the while
loop will always be true
; therefore, the loop continues to run.
Stop when n = 0. n is now 4
Stop when n = 0. n is now 3
Stop when n = 0. n is now 2
Stop when n = 0. n is now 1
Stop when n = 0. n is now 0
As soon as n
becomes zero, zero coerces to false
and the loop terminates.
-
An operator is said to be “unary” if it requires only one operand ↩